﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Text;
using System.ComponentModel;
using System.Data.Services.Client;
using System.IO.IsolatedStorage;
using Yelper.API;
using System.Collections.ObjectModel;
using Microsoft.Phone.Controls;
using System.Windows.Threading;

namespace Yelper.Phone {
    public class EventArgs<T> : EventArgs {
        public T Value { get; private set; }
        public EventArgs(T value) {
            Value = value;
        }
    }

    public enum LoginStatus {
        LoggedIn,
        LoggedOut
    }

    public class YelperApp {
        public event EventHandler<AsyncCompletedEventArgs> CheckCredentialsCompleted;
        public event EventHandler<AsyncCompletedEventArgs> AddYelpCompleted;
        public event EventHandler<EventArgs<LoginStatus>> LoginStatusChanged;
        private const string API_LOCATION = "http://api.yelper.eu/YelperDataService.svc/";
        private YelperEntities context = new YelperEntities(new Uri(API_LOCATION, UriKind.Absolute));
        private bool isLoadingMyTimeline, isLoadingMyMentions, isLoadingPublicTimeline, isSaving;
        private LoginStatus loginStatus;
        private string password;

        private ObservableCollection<PivotItem> pivotItems = new ObservableCollection<PivotItem>();
        private PivotItem publicTimelinePivotItem, mentionsPivotItem, myTimelinePivotItem;       

        #region Properties
        public LoginStatus LoginStatus {
            get { return loginStatus; }
            set {
                if (loginStatus != value) {
                    loginStatus = value;
                    OnLoginStatusChanged(value);
                }
            }
        }
        public string Username { get; private set; }        
		public DataServiceCollection<Yelp> MyMentions { get; private set; }
        public DataServiceCollection<Yelp> MyTimeline { get; private set; }
        public DataServiceCollection<Yelp> PublicTimeline { get; private set; }
        public Yelp SelectedYelp { get; set; }
        public User SelectedUser { get; set; }
        public bool HasCredentials {
            get { return !String.IsNullOrEmpty(Username) && !String.IsNullOrEmpty(password); }
        }
        
        public ObservableCollection<PivotItem> PivotItems {
            get { return pivotItems; }
        }
        #endregion

        #region Api HelperFunction
        public void LoadPublicTimelineAsync() {
            if (!isLoadingPublicTimeline) {
                isLoadingPublicTimeline = true;
                PublicTimeline.LoadAsync(new Uri("/Yelps?$orderby=YelpDate desc&$expand=User&$top=30", UriKind.Relative));
            }
        }
        private void PublicTimeline_LoadCompleted(object sender, LoadCompletedEventArgs e) {
            isLoadingPublicTimeline = false;
        }
        public void LoadMyTimelineAsync() {
            if (!isLoadingMyTimeline) {
                isLoadingMyTimeline = true;
                MyTimeline.LoadAsync(new Uri("/MyTimeline?$orderby=YelpDate desc&$expand=User&$top=30", UriKind.Relative));
            }
            
        }
        private void MyTimeline_LoadCompleted(object sender, LoadCompletedEventArgs e) {
            isLoadingMyTimeline = false;
        }
        public void LoadMyMentionsAsync() {
            if (!isLoadingMyMentions) {
                isLoadingMyMentions = true;
                MyMentions.LoadAsync(new Uri("/MyMentions?$orderby=YelpDate desc&$expand=User&$top=30", UriKind.Relative));
            }
        }
        private void MyMentions_LoadCompleted(object sender, LoadCompletedEventArgs e) {
            isLoadingMyMentions = false;
        }
        public void AddYelpAsync(Yelp yelp) {
            if (!isSaving) {
                context.AddObject("Yelps", yelp);
                YelperStatic.App.Context.BeginSaveChanges(AddYelpAsyncCallback, null);
            }
        }
        private void AddYelpAsyncCallback(IAsyncResult result) {
            try {
                var response = YelperStatic.App.Context.EndSaveChanges(result);
                OnAddYelpCompleted(null);
            } catch (Exception e) { 
                OnAddYelpCompleted(e);
            }
        }
        #endregion


        protected virtual void OnAddYelpCompleted(Exception e) {
            if (AddYelpCompleted != null) {
                AddYelpCompleted(null, new AsyncCompletedEventArgs(e, false, null));
            }
        }

        public YelperApp() {
            LoginStatus = Yelper.Phone.LoginStatus.LoggedOut;

            /*Add eventhandlers*/
            context.SendingRequest += new EventHandler<SendingRequestEventArgs>(context_SendingRequest);
            PublicTimeline = new DataServiceCollection<Yelp>(context);
            MyTimeline = new DataServiceCollection<Yelp>(context);            
            MyMentions = new DataServiceCollection<Yelp>(context);
            PublicTimeline.LoadCompleted += new EventHandler<LoadCompletedEventArgs>(PublicTimeline_LoadCompleted);
            MyTimeline.LoadCompleted += new EventHandler<LoadCompletedEventArgs>(MyTimeline_LoadCompleted);
            MyMentions.LoadCompleted += new EventHandler<LoadCompletedEventArgs>(MyMentions_LoadCompleted);            

            /*Create pivot items*/
            CreatePivotItems();
            pivotItems.Add(publicTimelinePivotItem);            

            /*Load settings*/
            LoadCredentials();            
        }

        private void CreatePivotItems() {
            publicTimelinePivotItem = new PivotItem();
            publicTimelinePivotItem.Header = "public timeline";
            publicTimelinePivotItem.Content = new PublicTimelineControl();
            publicTimelinePivotItem.DataContext = this;

            mentionsPivotItem = new PivotItem();
            mentionsPivotItem.Header = "mentions";
            mentionsPivotItem.Content = new MentionsControl();
            mentionsPivotItem.DataContext = this;

            myTimelinePivotItem = new PivotItem();
            myTimelinePivotItem.Header = "my timeline";
            myTimelinePivotItem.Content = new MyTimelineControl();
            myTimelinePivotItem.DataContext = this;
        }
        
        private void context_SendingRequest(object sender, SendingRequestEventArgs e) {
            e.RequestHeaders["Authorization"] = "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(Username + ":" + password));
        }

        public YelperEntities Context {
            get { return context; }
        }        

        public void CheckCredentialsAsync(string username, string password) {
            try {
                /* Create an HTTP request to check the credentials */
                var req = HttpWebRequest.CreateHttp(API_LOCATION + "MyTimeline?$top=0");
                req.Credentials = new NetworkCredential(username, password);

                req.BeginGetResponse(new AsyncCallback((result) => {
                    /* Callback function */
                    try {
                        /* Cast our state object back to an HttpWebRequest to retrieve our HttpWebResponse*/
                        var request = (HttpWebRequest)result.AsyncState;
                        var response = (HttpWebResponse)request.EndGetResponse(result);

                        if (response.StatusCode == HttpStatusCode.OK) {
                            /* Credentials are correct */
                            this.Username = username;
                            this.password = password;
                            OnCheckCredentialsCompleted(null);
                        } else {
                            /* Credentials are wrong / Another problem */
                            OnCheckCredentialsCompleted(new Exception());
                        }
                    } catch (Exception e) {
                        /* An error occured while trying to retrieve the HttpWebResponse */
                        System.Diagnostics.Debug.WriteLine(e.ToString());
                        OnCheckCredentialsCompleted(new Exception());
                    }
                }), req);
            } catch {
                /* An error occured while trying to send the HttpWebRequest */
                OnCheckCredentialsCompleted(new Exception());
            }
        }
        public void Logout() {
            Deployment.Current.Dispatcher.BeginInvoke(() => {
                pivotItems.Remove(myTimelinePivotItem);
                pivotItems.Remove(mentionsPivotItem);
            });
            ClearCredentials();
            LoginStatus = Phone.LoginStatus.LoggedOut;
        }

        protected virtual void OnCheckCredentialsCompleted(Exception e) {           
            if (e == null) {
                LoginStatus = Phone.LoginStatus.LoggedIn;
                LoadMyTimelineAsync();
                LoadMyMentionsAsync();
            } else {
                LoginStatus = Phone.LoginStatus.LoggedOut;
            }

            /* Surrounded with try-cath to catch exception that were generated in an EventHandler */
            try {
                Deployment.Current.Dispatcher.BeginInvoke(() => {
                    if (e == null) {
                        /* login was succesful, check if we need to add an pivotitem! */
                        if (!pivotItems.Contains(myTimelinePivotItem)) {
                            pivotItems.Insert(1, myTimelinePivotItem);
                        }
                        if (!pivotItems.Contains(mentionsPivotItem)) {
                            pivotItems.Insert(2, mentionsPivotItem);
                        }
                    } else {
                        pivotItems.Remove(myTimelinePivotItem);
                        pivotItems.Remove(mentionsPivotItem);                        
                    }
                });
                if (CheckCredentialsCompleted != null) {
                    CheckCredentialsCompleted(null, new AsyncCompletedEventArgs(e, false, null));
                }
            } catch {            
            }
        }
        protected virtual void OnLoginStatusChanged(LoginStatus newStatus) {
            if (LoginStatusChanged != null) {                
                LoginStatusChanged(this, new EventArgs<LoginStatus>(newStatus));
            }
        }

        public void Load() {            
            SelectedUser = SettingsFacade.SelectedUser;
            SelectedYelp = SettingsFacade.SelectedYelp;
            Username = SettingsFacade.UsernameTemp;
            password = SettingsFacade.PasswordTemp;            
        }
        public void Save() {
            SettingsFacade.SelectedUser = SelectedUser;
            SettingsFacade.SelectedYelp = SelectedYelp;
            SettingsFacade.PasswordTemp = password;
            SettingsFacade.UsernameTemp = Username;
            SettingsFacade.Save();
        }

        public void ClearCredentials() {
            Username = null;
            password = null;
            SettingsFacade.ClearCredentials();
        }
        public void SaveCredentials() {
            SettingsFacade.Password = password;
            SettingsFacade.Username = Username;
            SettingsFacade.Save();
        }
        public void LoadCredentials() {
            Username = SettingsFacade.Username;
            password = SettingsFacade.Password;
        }

        internal void CheckCurrentCredentialsAsync() {
            if (!HasCredentials) {
                return;
            } else {
                CheckCredentialsAsync(Username, password);
            }
        }
    }
}
